from abc import ABC, abstractmethod

# 1. 运行代码
# 输出如下：
# 用户 101 借阅了图书 B1001
# 发送邮件给用户 101：你已借阅图书 B1001
# 用户 101 归还了图书 B1001
# 发送邮件给用户 101：你已归还图书 B1001

# 切换到短信通知服务...

# 用户 102 借阅了图书 B1002
# 发送短信给用户 102：你已借阅图书 B1002
# 用户 102 归还了图书 B1002
# 发送短信给用户 102：你已归还图书 B1002

# 2. 指出该代码体现了哪个原则
# 体现了依赖倒置原则（Dependency Inversion Principle, DIP）

# 3. 请说明该代码是如何体现该原则
# 依赖倒置原则指出，高层模块不应该依赖于低层模块，两者都应该依赖于抽象；抽象不应该依赖于细节，细节应该依赖于抽象。
# 在这个例子中：
# - `LibraryManagementSystem` 是高层模块，它依赖于抽象的 `NotificationService` 接口，而不是具体的 `EmailNotificationService` 或 `SMSNotificationService`。
# - `EmailNotificationService` 和 `SMSNotificationService` 是低层模块，它们实现了 `NotificationService` 接口。
# - 这种设计使得 `LibraryManagementSystem` 可以在不修改代码的情况下，通过传入不同的通知服务对象来改变通知方式，从而提高了系统的灵活性和可扩展性。

# 抽象通知接口
class NotificationService(ABC):
    @abstractmethod
    def notify(self, user_id, message):
        pass

# 具体的电子邮件通知实现
class EmailNotificationService(NotificationService):
    def notify(self, user_id, message):
        print(f"发送邮件给用户 {user_id}：{message}")

# 具体的短信通知实现
class SMSNotificationService(NotificationService):
    def notify(self, user_id, message):
        print(f"发送短信给用户 {user_id}：{message}")

# 图书管理系统，依赖于抽象的NotificationService接口
class LibraryManagementSystem:
    def __init__(self, notification_service: NotificationService):
        self.notification_service = notification_service

    def borrow_book(self, user_id, book_id):
        # 借书逻辑
        print(f"用户 {user_id} 借阅了图书 {book_id}")
        # 通知用户
        self.notification_service.notify(user_id, f"你已借阅图书 {book_id}")

    def return_book(self, user_id, book_id):
        # 还书逻辑
        print(f"用户 {user_id} 归还了图书 {book_id}")
        # 通知用户
        self.notification_service.notify(user_id, f"你已归还图书 {book_id}")

# 测试示例
if __name__ == "__main__":
    # 使用电子邮件通知服务
    email_service = EmailNotificationService()
    library_system = LibraryManagementSystem(email_service)
    library_system.borrow_book(user_id=101, book_id="B1001")
    library_system.return_book(user_id=101, book_id="B1001")

    print("\n切换到短信通知服务...\n")

    # 使用短信通知服务
    sms_service = SMSNotificationService()
    library_system = LibraryManagementSystem(sms_service)
    library_system.borrow_book(user_id=102, book_id="B1002")
    library_system.return_book(user_id=102, book_id="B1002")